import itertools
import collections

class Context(object):
    """Global application context."""

    def __init__(self):
        self.plugin_contexts = set()

    def get_interface(self, iface_name):
        for plug_ctx in self.plugin_contexts:
            iface = plug_ctx.get_interface(iface_name)
            if iface:
                return iface

    def get_implementations(self, iface_name):
        for plug_ctx in self.plugin_contexts:
            for impl in plug_ctx.get_implementations(iface_name):
                yield impl

    def get_implementation(self, iface_name, impl_name):
        for plug_ctx in self.plugin_contexts:
            impl = plug_ctx.get_implementation(iface_name, impl_name)
            if impl:
                return impl

    def new_plugin_context(self):
        plug_ctx = PluginContext(self)
        self.plugin_contexts.add(plug_ctx)
        return plug_ctx

    def remove_plugin_context(self, plug_ctx):
        self.plugin_contexts.remove(plug_ctx)

class PluginContext(object):
    def __init__(self, global_ctx):
        self._global_ctx = global_ctx
        self.active = False
        self.interfaces = {}
        self.implementations = collections.defaultdict(dict)

    def add_interface(self, iface):
        """Add an interface."""

        self.interfaces[iface.name] = iface

    def add_implementation(self, impl):
        """Add an interface."""

        self.implementations[impl.iface_name][impl.name] = impl

    def get_interface(self, iface_name):
        if self.active:
            if iface_name in self.interfaces:
                return self.interfaces[iface_name]

    def get_implementations(self, iface_name):
        if self.active:
            if iface_name in self.implementations:
                for impl in self.implementations[iface_name].values():
                    yield impl

    def get_implementation(self, iface_name, impl_name):
        if self.active:
            if iface_name in self.implementations:
                if impl_name in self.implementations[iface_name]:
                        return self.implementations[iface_name][impl_name]

    def get_all_implementations(self):
        """Return all implementations defined by the plugin."""
        return itertools.chain(*(iface_impls.values()
                             for iface_impls in self.implementations.values()))

    def activate(self):
        """Export everything to the application."""
        self.active = True

        self._activate_ifaces()
        self._activate_implementations()

    def deactivate(self):
        """Stop exporting everything to the application."""
        self.active = False

        self._deactivate_ifaces()
        self._deactivate_implementations()

    def _activate_ifaces(self):
        for iface in self.interfaces.values():
            iface.activate()
    def _activate_implementations(self):
        for impl in self.get_all_implementations():
            impl.activate()
    def _deactivate_ifaces(self):
        for iface in self.interfaces.values():
            iface.deactivate()
    def _deactivate_implementations(self):
        for impl in self.get_all_implementations():
            impl.deactivate()
